#ifndef JOB_H
#define JOB_H

#include <QtCore>

#include "../filehandling/FileType.h"
#include "PeerInfo.h"

// semafory
#include "../network/monitor.h"

namespace Client {

/**
 * Status zadania
 **/
enum JobStatus {
	jsActive,	///< zadanie uruchomione, połączenie nawiązane, fragmenty sa pobierane
	jsPending,	///< zadanie uruchomione, oczekuje na pojawienie się aktywnych posiadaczy
	jsPaused,	///< zadanie wstrzymane, ale bez zrywania połączeń z klientami
	jsStopped,	///< zadanie zatrzymane, połaczenia przerwane
	jsFinished	///< ukończono pobieranie pliku
};

/**
 * @brief Zadanie pobierania konkretnego pliku.
 *
 * Przechowuje status zadania oraz pobrane fragmenty. Udostępnia operacje
 * związane z zarządzaniem zadaniami (zatrzymywanie, uruchamianie itp).
 **/
class Job {
public:
	/*
		Publicznie dostępne składowe
	*/

	/// nazwa ściąganego/udostępnianego pliku
	QString fname;

	/// suma kontrolna
	QByteArray hash;

	/// rozmiar pliku
	int size;

	/// typ pliku
	Common::FileType type;

	/// rozmiar pakietu
	int chunk_size;

	/// całkowita ilość fragmentów
	int chunks_count;

	/// ilość pobranych fragmentów
	int chunks_done;

	/// aktualny status
	JobStatus status;

	/// ilość podłączonych dawców
	int seeds_count;

	/// zapamiętana ilość dawców w celu wyświetlania na liście zadań
	int seeds_count_keep;

	/// lista dawców
	QList<PeerInfo> seeds;

	/// ile kwantów czasu pozostało do następnej aktualizacji seedów
	int age;

	/*
		metody
	*/

	/**
	 * Konstruktor.
	 **/
	Job();

	/**
	 * Destruktor
	 **/
	~Job();

	/**
	 * Zwraca numer pierwszego niepobranego i niepobieranego jeszcze fragmentu.
	 **/
	int getNextFreeChunk(int locker = -1);

	/**
	 * Dodaje ściągnięty fragment do pliku oraz zwalnia slot zajmowany przez
	 * kienta o danym id.
	 **/
	bool addChunk(int chunk, QByteArray chunk_data, int seed_id);

	/**
	 * Zwalnia slot klienta o danym id. Wywoływana w momencie, gdy no, klient się rozłączy
	 * bądź wysłany przez niego fragment pliku będzie błędny - wtedy klient jest zwalniany
	 * bez dokonywania zadnych zmian w strukturze pliku. Wykonywane jest też zwolnieni
	 * ewentualnego fragmentu zablokowanego przez tego klienta.
	 *
	 * @param remove określa, czy dawcę należy usunąć z listy
	 **/
	void freeSeed(int client_id, bool remove = false);

	/**
	 * Dodaje informacje o nowym, aktywnym dawcy do listy przechowywanej w zadaniu.
	 **/
	void addSeed(PeerInfo peer);

	/**
	 * Oznacza dany fragment jako zablokowany (wysłane żądanie ściągania)
	 **/
	void lockChunk(int id, int client);

	/**
	 * Zwraca liczbę pakietów zarezerwowanych do ściągnięcia (czyli, praktycznie mówiąc, pobieranych)
	 **/
	int lockCount();

	/**
	 * Składa plik ze wszystkich pobranych fragmentów
	 **/
	bool merge(QString fname);


private:
	/// lista pobranych fragmentów
	QList<int> chunks;
	QMap<int, int> locked;
	QFile * disk_file;

	/// semafor synchronizujący zapis danych na dysku
	Semaphore mutex;
};

} // namespace Client

#endif // JOB_H
